﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;
using ThreeByte.ActiveDeck.Config;
using System.Xml.Linq;
using System.Net;
using System.Xml;
using ThreeByte.ActiveDeck.Service;
using ThreeByte.Media;
using ThreeByte.ActiveDeck.Data;
using System.Reflection;
using log4net;
using ThreeByte.ActiveDeck.AddIn.Config;
using ThreeByte.ActiveDeck.AddIn.Controls;
using ThreeByte.ActiveDeck.AddIn.Content.Controls;
using System.Collections.ObjectModel;
using System.Collections;

namespace ThreeByte.ActiveDeck.Controls {
    /// <summary>
    /// Interaction logic for SetupControl.xaml
    /// </summary>
    public partial class SetupControl : UserControl {
        private static readonly ILog log = LogManager.GetLogger(typeof(SetupControl));
        private static readonly XNamespace ns = ServiceConfiguration.NAMESPACE;

        //Must make sure this is set before we do anything
        public CoreConfig Config { get; private set; }

        public event EventHandler Close;

        private GetWebConfigTask getWebConfigTask;
        private Dictionary<int, ObservableCollection<GroupUser>> UserCollectionDict = new Dictionary<int, ObservableCollection<GroupUser>>();
        private Dictionary<int, ObservableCollection<GroupUser>> ModifiedCollectionDict = new Dictionary<int, ObservableCollection<GroupUser>>();

        private ObservableCollection<PresentationGroup> ModifiedPresentationGroups = new ObservableCollection<PresentationGroup>();

        public SetupControl(CoreConfig config) {
            InitializeComponent();
            Config = config;
            DataContext = Config;

            UserNameTextBox.Text = Config.PresenterLogin.UserName;
            PresenterPasswordTextBox.Password = Config.PresenterLogin.Password;
            if(config.Logo != null) {
                iconImage.Source = config.Logo.Image;
            }
            if(config.HomePage != null) {
                HomePageImage.Source = config.HomePage.Image;
            }
            if(config.EndPage != null) {
                EndPageImage.Source = config.EndPage.Image;
            }
            PreviewOverlayBrush.Color = config.DefaultButtonOverlayColor;

            UserAccessComboBox.SelectedIndex = (int)config.UserAccess;

            ShowCheckBox.DataContext = Config.Environment;

            //Set initial Kiosk Mode parameters
            if(config.KioskConfig != null) {
                KioskModeCheckBox.IsChecked = config.KioskConfig.Enabled;
                if(config.ContainsPageId(config.KioskConfig.AttractModePage)) {
                    AttractModePageName.Text = string.Format("Page {0}", config.KioskConfig.AttractModePage);
                }
                if(config.ContainsPageId(config.KioskConfig.FirstUserPage)) {
                    FirstUserPageName.Text = string.Format("Page {0}", config.KioskConfig.FirstUserPage);
                }
                IdleTimeout.Text = config.KioskConfig.Timeout.ToString();
                AutoUpdatePresentation.IsChecked = config.KioskConfig.AutoUpdate;
            } else {
                //Add a default timeout period
                IdleTimeout.Text = @"00:02:00";
                AutoUpdatePresentation.IsChecked = true;
            }

            getWebConfigTask = new GetWebConfigTask(Config);
            getWebConfigTask.Completed += new EventHandler(getGroupsTask_Completed);
            getWebConfigTask.Go();
        }

        void getGroupsTask_Completed(object sender, EventArgs e) {
            if(getWebConfigTask.HasError) {
                //do something
                log.WarnFormat("Get Groups Task failed: {0}", getWebConfigTask.Error);
                return;
            }

            //Check available version against this add-in's version
            Version thisVer = Assembly.GetExecutingAssembly().GetName().Version;
            VersionNumberRun.Text = string.Format("Version {0}", thisVer);
            Version availableVersion = getWebConfigTask.availableVersion;

            if(availableVersion != null) {
                if(availableVersion > thisVer) {
                    log.DebugFormat("New version available: {0}", availableVersion);
                    UpdateTextBlock.Visibility = Visibility.Visible;
                } else {
                    log.DebugFormat("This version is up to date: {0} >= {1}", thisVer, availableVersion);
                }
            }

            UserCollectionDict = getWebConfigTask.UserCollectionDict;

            foreach(int groupID in UserCollectionDict.Keys) {

                ObservableCollection<GroupUser> users = new ObservableCollection<GroupUser>();
                foreach(GroupUser user in UserCollectionDict[groupID]) {
                    users.Add(user);
                }

                ModifiedCollectionDict.Add(groupID, users);
            }

            foreach(PresentationGroup pg in Config.PresentationGroups) {
                ModifiedPresentationGroups.Add(pg);
            }

            GroupsList.DataContext = ModifiedPresentationGroups;

            GroupsTab.IsEnabled = true;
        }

        private void Hyperlink_Click(object sender, RoutedEventArgs e) {
            Hyperlink link = (Hyperlink)sender;
            try {
                string webAddress = link.NavigateUri.AbsoluteUri;
                ProcessStartInfo ps = new ProcessStartInfo(webAddress);
                ps.UseShellExecute = true;
                Process.Start(ps);
            } catch(Exception ex) {
                log.Error("Could not open address", ex);
            }
        }


        private void TestLogin_Click(object sender, RoutedEventArgs e) {
            //TODO: Test the login process
            Config.PresenterLogin.UserName = UserNameTextBox.Text;
            Config.PresenterLogin.Password = PresenterPasswordTextBox.Password;
            HidePasswordIcon();

            WebServiceClient client = new WebServiceClient(Config.PresenterLogin);

            try {
                bool result = client.TestLogin();

                if(result) {
                    GoodPasswordIcon.Visibility = Visibility.Visible;
                } else {
                    BadPasswordIcon.Visibility = Visibility.Visible;
                }
            } catch(System.Configuration.ConfigurationException configEx) {
                MessageBox.Show("There was a fatal error with the configuration subsystem.  Please contact support.", "Configuration Exception");
                log.Fatal("Configuration Exception", configEx);
            } catch(Exception ex) {
                PasswordErrorIcon.Visibility = Visibility.Visible;
                PasswordErrorIcon.ToolTip = ex.Message;
                log.Error("PasswordVerify Error", ex);
            }

        }

        private void HidePasswordIcon() {
            GoodPasswordIcon.Visibility = Visibility.Hidden;
            BadPasswordIcon.Visibility = Visibility.Hidden;
            PasswordErrorIcon.Visibility = Visibility.Hidden;
            PasswordErrorIcon.ToolTip = null;
        }

        private void OKButton_Click(object sender, RoutedEventArgs e) {
            //Save changes and close the window
            Config.PresenterLogin.UserName = UserNameTextBox.Text;
            Config.PresenterLogin.Password = PresenterPasswordTextBox.Password;
            Config.UserAccess = (UserAccess)(UserAccessComboBox.SelectedIndex);

            //Store the logo if it was updated
            if(iconUpdated) {
                Config.Logo = new GraphicResource(new Guid(), "Logo", ImageUtil.SaveToBitmapSource(IconImageFrame, new Size(96, 96)));
            }

            if(homePageUpdated) {
                Config.HomePage = new GraphicResource(ImageUtil.SaveToBitmapSource(HomePageImageFrame, new Size(768, 1024)), "HomePage", ImageType.JPEG);
            }

            if(endPageUpdated) {
                Config.EndPage = new GraphicResource(ImageUtil.SaveToBitmapSource(EndPageImageFrame, new Size(768, 1024)), "EndPage", ImageType.JPEG);
            }

            //Update the Kiosk Mode parameters
            TimeSpan newTimeout;
            if(KioskModeCheckBox.IsChecked ?? false) {
                //Create a config if it doesn't exist already
                if(Config.KioskConfig == null) {
                    Config.KioskConfig = new KioskConfiguration();
                }

                if(!(TimeSpan.TryParse(IdleTimeout.Text, out newTimeout))) {
                    MessageBox.Show("Please enter a valid duration (xx:xx:xx)", "Timeout Error");
                    IdleTimeout.Focus();
                    IdleTimeout.SelectAll();
                    return;
                } else {
                    Config.KioskConfig.Timeout = newTimeout;
                }

                Config.KioskConfig.Enabled = true;
                if(newAttractModePage != 0) {
                    Config.KioskConfig.AttractModeSection = newAttractModeSection;
                    Config.KioskConfig.AttractModePage = newAttractModePage;
                }
                if(newUserModePage != 0) {
                    Config.KioskConfig.FirstUserSection = newUserModeSection;
                    Config.KioskConfig.FirstUserPage = newUserModePage;
                }
                Config.KioskConfig.AutoUpdate = AutoUpdatePresentation.IsChecked ?? false;

            } else {
                if(Config.KioskConfig != null) {
                    Config.KioskConfig.Enabled = false;
                }
            }

            Dictionary<int, ObservableCollection<GroupUser>> userAddDiff = UsersToAdd(UserCollectionDict, ModifiedCollectionDict);

            if(userAddDiff.Count > 0) {
                WebServiceClient client = new WebServiceClient(Config.PresenterLogin);

                foreach(int k in userAddDiff.Keys) {
                    List<string> users = new List<string>();
                    foreach(GroupUser gu in userAddDiff[k]) {
                        if(!gu.Username.Equals(""))
                            users.Add(gu.Username);
                    }
                    client.SetUserGroup(Config.ID, users, k);
                }


                //List<int> groupIDs = ModifiedCollectionDict.Keys.Distinct().ToList();
                //foreach(int groupID in groupIDs) {
                //    List<string> usernames = new List<string>();
                //    foreach(GroupUser gu in ModifiedCollectionDict[groupID]) {
                //        if(!gu.Username.Equals(""))
                //            usernames.Add(gu.Username);
                //    }
                //    client.SetUserGroup(Config.ID, usernames, groupID);
                //}
            }

            Dictionary<int, ObservableCollection<GroupUser>> userRemoveDiff = UsersToRemove(UserCollectionDict, ModifiedCollectionDict);

            if(userRemoveDiff.Count > 0) {
                WebServiceClient client = new WebServiceClient(Config.PresenterLogin);
                foreach(int k in userRemoveDiff.Keys) {
                    int groupID = k;

                    List<string> users = new List<string>();
                    foreach(GroupUser gu in userRemoveDiff[k]) {
                        users.Add(gu.Username);
                    }

                    if(users.Count > 0) {
                        client.RemoveUsersFromGroup(Config.ID, users, groupID);
                    }
                }
            }

            ObservableCollection<PresentationGroup> addedGroupDiff = AddedGroups(ModifiedPresentationGroups);

            if(addedGroupDiff.Count > 0) {
                foreach(PresentationGroup pg in addedGroupDiff) {
                    Config.PresentationGroups.Add(pg);    
                }
                
            }

            ObservableCollection<PresentationGroup> groupDiff = RemovedGroups(ModifiedPresentationGroups);

            if(groupDiff.Count > 0) {
                WebServiceClient client = new WebServiceClient(Config.PresenterLogin);
                List<int> groupIDsToBeRemoved = new List<int>();
                foreach(PresentationGroup pg in groupDiff) {
                    groupIDsToBeRemoved.Add(pg.ID);
                    Config.PresentationGroups.Remove(pg);
                }

                client.RemovePresentationGroups(Config.ID, groupIDsToBeRemoved);
            }


            if(Close != null) {
                Close(this, EventArgs.Empty);
            }
        }

        private void PresenterPasswordTextBox_PasswordChanged(object sender, RoutedEventArgs e) {
            HidePasswordIcon();
        }

        private void NewPresentation_Click(object sender, RoutedEventArgs e) {
            NetworkCredential creds = new NetworkCredential(UserNameTextBox.Text, PresenterPasswordTextBox.Password);
            NamePresentationForm newPresentationForm = new NamePresentationForm(Config, creds);
            System.Windows.Forms.DialogResult result = newPresentationForm.ShowDialog();

            //If this succeeds, make sure to update the controls
            if(result == System.Windows.Forms.DialogResult.OK) {
                UserNameTextBox.Text = Config.PresenterLogin.UserName;
                PresenterPasswordTextBox.Password = Config.PresenterLogin.Password;
            }

        }

        private void RenamePresentation_Click(object sender, RoutedEventArgs e) {
            NetworkCredential creds = new NetworkCredential(UserNameTextBox.Text, PresenterPasswordTextBox.Password);
            NamePresentationForm newPresentationForm = new NamePresentationForm(Config, creds, true);
            System.Windows.Forms.DialogResult result = newPresentationForm.ShowDialog();

            if(result == System.Windows.Forms.DialogResult.OK) {
                UserNameTextBox.Text = Config.PresenterLogin.UserName;
                PresenterPasswordTextBox.Password = Config.PresenterLogin.Password;
            }
        }

        private void PresenterPasswordTextBox_PreviewKeyDown(object sender, KeyEventArgs e) {
            if(e.Key == Key.Enter || e.Key == Key.Return) {
                TestLogin_Click(null, null);
            }
        }

        private bool iconUpdated = false;
        private bool homePageUpdated = false;
        private bool endPageUpdated = false;

        private void iconImage_DragEnter(object sender, DragEventArgs e) {
            if(e.Data.GetDataPresent(DataFormats.FileDrop)) {
                e.Effects = DragDropEffects.Link;
            } else {
                e.Effects = DragDropEffects.None;
            }
            e.Handled = true;
        }

        private void iconImage_DragOver(object sender, DragEventArgs e) {
            if(e.Data.GetDataPresent(DataFormats.FileDrop)) {
                e.Effects = DragDropEffects.Link;
            } else {
                e.Effects = DragDropEffects.None;
            }
            e.Handled = true;
        }

        private void iconImage_DragLeave(object sender, DragEventArgs e) {
            e.Handled = true;
        }

        private void iconImage_Drop(object sender, DragEventArgs e) {
            string filepath = ((string[])e.Data.GetData(DataFormats.FileDrop))[0];
            iconUpdated = LoadImageSource(filepath, iconImage);
        }

        private bool LoadImageSource(string filepath, Image image) {
            //Open the path, if possible and create the image
            try {
                BitmapImage newImage = new BitmapImage();
                newImage.BeginInit();
                newImage.CacheOption = BitmapCacheOption.OnLoad;
                newImage.UriSource = new Uri(filepath);
                newImage.EndInit();
                newImage.Freeze();

                image.Source = newImage;
                return true;
            } catch {
                MessageBox.Show("Unable to load this file.  Make sure you have chosen a valid image file.");
                return false;
            }
        }

        #region Resources

        #region Presentation Icons
        private void iconImagePaste_Click(object sender, RoutedEventArgs e) {
            if(!Clipboard.ContainsImage()) {
                return;
            }

            iconImage.Source = Clipboard.GetImage();
            iconUpdated = true;
        }

        private void iconImageChoose_Click(object sender, RoutedEventArgs e) {
            Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog();
            openFileDialog.Filter = "Image Files |*.bmp;*.jpg;*.png;*.tif;*.gif|All Files|*.*";
            openFileDialog.ValidateNames = true;
            openFileDialog.Multiselect = false;
            bool? result = openFileDialog.ShowDialog();

            if(result != null && (bool)result) {
                //log.Debug(openFileDialog.FileName);
                //Load the icon
                iconUpdated = LoadImageSource(openFileDialog.FileName, iconImage);
            }
        }
        #endregion Presentation Icon

        private void HomeImageChoose_Click(object sender, RoutedEventArgs e) {
            Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog();
            openFileDialog.Filter = "Image Files |*.bmp;*.jpg;*.png;*.tif;*.gif|All Files|*.*";
            openFileDialog.ValidateNames = true;
            openFileDialog.Multiselect = false;
            bool? result = openFileDialog.ShowDialog();

            if(result != null && (bool)result) {
                homePageUpdated = LoadImageSource(openFileDialog.FileName, HomePageImage);
            }
        }

        private void HomeImagePaste_Click(object sender, RoutedEventArgs e) {
            if(!Clipboard.ContainsImage()) {
                return;
            }

            HomePageImage.Source = Clipboard.GetImage();
            homePageUpdated = true;
        }

        private void EndImageChoose_Click(object sender, RoutedEventArgs e) {
            Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog();
            openFileDialog.Filter = "Image Files |*.bmp;*.jpg;*.png;*.tif;*.gif|All Files|*.*";
            openFileDialog.ValidateNames = true;
            openFileDialog.Multiselect = false;
            bool? result = openFileDialog.ShowDialog();

            if(result != null && (bool)result) {
                endPageUpdated = LoadImageSource(openFileDialog.FileName, EndPageImage);
            }
        }

        private void EndImagePaste_Click(object sender, RoutedEventArgs e) {
            if(!Clipboard.ContainsImage()) {
                return;
            }

            EndPageImage.Source = Clipboard.GetImage();
            endPageUpdated = true;
        }

        #endregion Resources


        private void DownloadNowButton_Click(object sender, RoutedEventArgs e) {
            //Open a new window with a background task
            if(!(Config.HasPresenterLogin)) {
                MessageBox.Show("Please enter your user credentials before downloading the update", "User Credentials");
                MainTabControl.SelectedIndex = 1;
                UserNameTextBox.SelectAll();
                UserNameTextBox.Focus();
                return;
            }

            DownloadAddInTask dltask = new DownloadAddInTask(new WebServiceClient(Config.PresenterLogin));
            dltask.Completed += new EventHandler(dltask_Completed);
            CancelHyperLink.Tag = dltask;
            CancelTextBlock.Visibility = Visibility.Visible;
            UpdateTextBlock.Visibility = Visibility.Collapsed;
            Cursor = Cursors.Wait;
            dltask.Go();
        }

        void dltask_Completed(object sender, EventArgs e) {
            DownloadAddInTask task = (DownloadAddInTask)sender;
            task.Completed -= dltask_Completed;
            log.Debug("Download complete");
            UpdateTextBlock.Visibility = Visibility.Collapsed;
            CancelTextBlock.Visibility = Visibility.Collapsed;
            Cursor = null;

            if(task.HasError) {
                log.Warn("There was an error downloading the file");
                return;
            }

            MessageBoxResult result = MessageBox.Show("A new version has finished downloading.  Would you like to install it now?", "Update", MessageBoxButton.YesNo);
            if(result != MessageBoxResult.Yes) {
                return;
            }

            try {
                ProcessStartInfo ps = new ProcessStartInfo(task.DownloadedFilePath);
                ps.UseShellExecute = true;
                Process.Start(ps);
            } catch(Exception ex) {
                log.Error("Could not run installer", ex);
            }
        }

        private void CancelDownloadButton_Click(object sender, RoutedEventArgs e) {
            Hyperlink cancelLink = (Hyperlink)sender;
            DownloadAddInTask task = cancelLink.Tag as DownloadAddInTask;
            if(task == null) {
                return;
            }
            task.Completed -= dltask_Completed;
            task.Cancel();
            cancelLink.Tag = null;
            UpdateTextBlock.Visibility = Visibility.Collapsed;
            CancelTextBlock.Visibility = Visibility.Collapsed;
            Cursor = null;
        }

        private int newAttractModeSection;
        private int newAttractModePage;
        private void SetNewAttractModePage(int sectionId, int pageId) {
            newAttractModeSection = sectionId;
            newAttractModePage = pageId;
            AttractModePageName.Text = string.Format("Page {0}", newAttractModePage);
        }

        private int newUserModeSection;
        private int newUserModePage;
        private void SetNewUserModePage(int sectionId, int pageId) {
            newUserModeSection = sectionId;
            newUserModePage = pageId;
            FirstUserPageName.Text = string.Format("Page {0}", newUserModePage);
        }

        private void ChooseAttractPageClick(object sender, RoutedEventArgs e) {
            CoreConfig currentConfig = Globals.ThisAddIn.GetCurrentConfig();
            PageChooserControl pageChooser = new PageChooserControl(currentConfig);
            HostForm newDialog = new HostForm(pageChooser);
            if(newDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
                PageConfig selectedPage = pageChooser.SelectedPage;
                SetNewAttractModePage(selectedPage.ParentSlideConfig.SlideId, selectedPage.PageId);
            }
        }

        private void ChooseUserPageClick(object sender, RoutedEventArgs e) {
            CoreConfig currentConfig = Globals.ThisAddIn.GetCurrentConfig();
            PageChooserControl pageChooser = new PageChooserControl(currentConfig);
            HostForm newDialog = new HostForm(pageChooser);
            if(newDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
                PageConfig selectedPage = pageChooser.SelectedPage;
                SetNewUserModePage(selectedPage.ParentSlideConfig.SlideId, selectedPage.PageId);
            }
        }

        private void ChoseOverlayColor_Click(object sender, MouseButtonEventArgs e) {
            //Open the color chooser
            CoreConfig currentConfig = Globals.ThisAddIn.GetCurrentConfig();
            ColorChooserControl colorChooser = new ColorChooserControl();
            colorChooser.SelectedColor = currentConfig.DefaultButtonOverlayColor;
            HostForm newDialog = new HostForm(colorChooser);
            if(newDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
                //Update the current default button overlay
                currentConfig.DefaultButtonOverlayColor = colorChooser.SelectedColor;
                PreviewOverlayBrush.Color = currentConfig.DefaultButtonOverlayColor;
            }
        }

        private void RefreshButtonOverlays_Click(object sender, RoutedEventArgs e) {
            //Refresh all current buttons

            CoreConfig currentConfig = Globals.ThisAddIn.GetCurrentConfig();
            Color overlayColor = currentConfig.DefaultButtonOverlayColor;

            //Iterate though all Sections/Pages
            foreach(SlideConfig slide in currentConfig.Slides) {
                foreach(PageConfig page in slide.Pages) {
                    if(page is NavigatorConfig) {
                        NavigatorConfig navPage = (NavigatorConfig)page;
                        foreach(DesignerControl control in navPage.Elements) {
                            if(control is DesignerButton) {
                                DesignerButton button = (DesignerButton)control;
                                button.ImageOn = DesignerButton.CreateShadedImage(button.ImageOff, overlayColor);
                            }
                        }
                    } else if(page is DesignerSlideConfig) {
                        DesignerSlideConfig designerPage = (DesignerSlideConfig)page;
                        foreach(DesignerControl control in designerPage.Elements) {
                            if(control is DesignerButton) {
                                DesignerButton button = (DesignerButton)control;
                                button.ImageOn = DesignerButton.CreateShadedImage(button.ImageOff, overlayColor);
                            }
                        }
                    }
                }
            }
        }

        private void AddGroupButton_Click(object sender, RoutedEventArgs e) {
            int maxID = 0;
            if(ModifiedPresentationGroups.Count > 0) {
                maxID = ModifiedPresentationGroups.Max(p => p.ID);
            }
            PresentationGroup pg = new PresentationGroup();
            pg.ID = ++maxID;

            ModifiedPresentationGroups.Add(pg);
        }

        private void GroupsList_SelectionChanged(object sender, SelectionChangedEventArgs e) {
            if(GroupsList.SelectedItems.Count > 0) {
                if(GroupsList.SelectedItems.Count > 1) {
                    AddUserButton.IsEnabled = false;
                    UsersList.ItemsSource = null;
                } else {
                    AddUserButton.IsEnabled = true;
                    PresentationGroup pg = (PresentationGroup)GroupsList.SelectedItem;

                    if(!ModifiedCollectionDict.ContainsKey(pg.ID)) {
                        ModifiedCollectionDict[pg.ID] = new ObservableCollection<GroupUser>();
                    }
                    UsersList.ItemsSource = ModifiedCollectionDict[pg.ID];
                }
            } else {
                UsersList.ItemsSource = null;
                AddUserButton.IsEnabled = false;
            }
        }

        private void AddUserButton_Click(object sender, RoutedEventArgs e) {
            //UsersList.Items.Add(new EditableListBoxItem());
            if(GroupsList.SelectedItem != null) {

                PresentationGroup pg = (PresentationGroup)GroupsList.SelectedItem;

                if(!ModifiedCollectionDict.ContainsKey(pg.ID)) {
                    ModifiedCollectionDict.Add(pg.ID, new ObservableCollection<GroupUser>());
                }
                ModifiedCollectionDict[pg.ID].Add(new GroupUser(""));
            }

        }

        private ObservableCollection<GroupUser> GetCachedUsersList(int groupID) {
            if(ModifiedCollectionDict.Count == 0)
                return null;

            if(ModifiedCollectionDict.ContainsKey(groupID))
                return null;

            return ModifiedCollectionDict[groupID];

        }

        private void PresentationMonitor_Unchecked(object sender, RoutedEventArgs e) {
            OperatorMonitorForm.ResetSizeAndPosition();
        }

        private void RemoveGroupButton_Click(object sender, RoutedEventArgs e) {
            

            List<PresentationGroup> groupsToBeRemoved = new List<PresentationGroup>();

            foreach(PresentationGroup group in GroupsList.Items) {
                if(GroupsList.SelectedItems.Contains(group)) {
                    groupsToBeRemoved.Add(group);
                }
            }

            foreach(PresentationGroup pg in groupsToBeRemoved) {
                if(ModifiedPresentationGroups.Contains(pg)) {
                    ModifiedPresentationGroups.Remove(pg);
                }
            }

            GroupsList.SelectedItems.Clear();
        }

        private void RemoveUserButton_Click(object sender, RoutedEventArgs e) {
            if(ModifiedCollectionDict.Count == 0)
                return;

            List<GroupUser> usersToBeRemoved = new List<GroupUser>();

            foreach(GroupUser user in UsersList.Items) {
                if(UsersList.SelectedItems.Contains(user)) {                    
                    usersToBeRemoved.Add(user);
                }
            }

            if(usersToBeRemoved.Count > 0) {
                int groupID = ((PresentationGroup)GroupsList.SelectedItem).ID;

                if(ModifiedCollectionDict.ContainsKey(groupID)) {
                    foreach(GroupUser u in usersToBeRemoved) {
                        ModifiedCollectionDict[groupID].Remove(u);
                    }
                }
            }
        }

        private Dictionary<int, ObservableCollection<GroupUser>> UsersToRemove(Dictionary<int, ObservableCollection<GroupUser>> original, Dictionary<int, ObservableCollection<GroupUser>> modified) {

            Dictionary<int, ObservableCollection<GroupUser>> difference = new Dictionary<int, ObservableCollection<GroupUser>>();

            foreach(int k in original.Keys) {
                if(!modified.ContainsKey(k)) {
                    difference.Add(k, original[k]);
                } else {
                    foreach(GroupUser user in original[k]) {
                        if(!modified[k].Contains(user)) {
                            if(difference.ContainsKey(k)) {
                                difference[k].Add(user);
                            } else {
                                difference.Add(k, new ObservableCollection<GroupUser>());
                                difference[k].Add(user);
                            }
                        }
                    }
                }
            }

            return difference;
        }

        private Dictionary<int, ObservableCollection<GroupUser>> UsersToAdd(Dictionary<int, ObservableCollection<GroupUser>> original, Dictionary<int, ObservableCollection<GroupUser>> modified) {

            Dictionary<int, ObservableCollection<GroupUser>> difference = new Dictionary<int, ObservableCollection<GroupUser>>();

            foreach(int k in modified.Keys) {
                if(!original.ContainsKey(k)) {
                    difference.Add(k, modified[k]);
                } else {
                    foreach(GroupUser user in modified[k]) {
                        if(!original[k].Contains(user)) {
                            if(difference.ContainsKey(k)) {
                                difference[k].Add(user);
                            } else {
                                difference.Add(k, new ObservableCollection<GroupUser>());
                                difference[k].Add(user);
                            }
                        }
                    }
                }
            }

            return difference;
        }

        private ObservableCollection<PresentationGroup> RemovedGroups(ObservableCollection<PresentationGroup> modifiedGroups) {

            IEnumerable<PresentationGroup> difference = Config.PresentationGroups.Except(modifiedGroups);

            return new ObservableCollection<PresentationGroup>(difference);
        }

        private ObservableCollection<PresentationGroup> AddedGroups(ObservableCollection<PresentationGroup> modifiedGroups) {

            IEnumerable<PresentationGroup> difference = modifiedGroups.Except(Config.PresentationGroups);

            return new ObservableCollection<PresentationGroup>(difference);
        }
    }



    public class GroupUser {
        public string Username { get; set; }

        public GroupUser(string username) {
            Username = username;
        }

    }
}
